use std::ops::Add;
use std::fmt;
fn main() {
    // 高级trait
    // 1. 关联类型
    pub trait Iterator {
        // 这就是关联类型, 是一个占位符, 它表示每次实现这个trait的时候, 都必须实现一个next方法,
        // 而该方法必然返回一个Option类型, 如果是Some(value), 则value必然是Item类型的值
        type Item;
        fn next(&mut self) -> Option<Self::Item>; // Self表示一个类型, self表示当前实例的不可变引用
    }
    struct Counter {
        current: i32,
        end: i32
    }
    impl Counter {
        // 关联函数new, 类似于js中的静态方法
        fn new() -> Counter {
            Counter {
                current: 12,
                end: 13
            }
        }
    }
    impl Iterator for Counter {
        type Item = i32; // 必须实现这个类型, Item就是个类型占位符
        // 这里的self表示的是实例
        fn next(&mut self) -> Option<Self::Item> {
            if self.current < self.end {
                let result = self.current;
                self.current = self.current + 1;
                return Some(result) // 这里不是最后一个表达式, 必须显式写return
            }
            None
        }
    }
    let mut counter = Counter::new();
    counter.current = 15;
    counter.end = 29;
    let a = counter.next();
    println!("a is: {:?}", a);

    // 跟泛型的不同之处就在于, 泛型参数可以反复实现一个类型, 而关联类型不行
    trait Iterator2<T> {
        fn next(&self) -> Option<T>;
    }
    struct Counter2 {
        current: i32,
        end: i32,
    }
    impl Iterator2<i32> for Counter2{
        fn next(&self) -> Option<i32> {
            Some(self.current)
        }
    }
    // 可以重复去实现
    impl Iterator2<String> for Counter2{
        fn next(&self) -> Option<String> {
            Some(String::from("hello"))
        }
    }

    // 2. 默认泛型参数和运算符重载
    // 可以为泛型参数定一个默认的类型, 常用语运算符重载
    // rust不允许创建自己的运算符或者重载任意运算符, 但可以实现std::ops列出的那些trait, 来重载一部分相应的运算符
    #[derive(Debug, PartialEq)] // 别忘了这句, rust编译器会自动实现这俩trait
    struct Pointer {
        x: i32,
        y: i32
    }
    // Add默认的泛型类型Rhs就是Self, 即实例本身
    impl Add for Pointer {
        type Output = Pointer;
        fn add(self, other: Pointer) -> Pointer {
            Pointer {
                x: self.x + other.x,
                y: self.y + other.y
            }
        }
    }
    // 这样, 我们就重载了运算符
    assert_eq!(Pointer {x: 1, y: 2} + Pointer {x: 1, y: 2}, Pointer {x: 2, y: 4});
    println!("ok");
    // 3. 完全限定语法(Fully Qualified Syntax)
    // 如何调用同名方法
    trait Pilot {
        fn fly(&self);
    }
    trait Wizard {
        fn fly(&self);
    }
    struct Human {
        name: String
    };

    // 实现飞行员的trait
    impl Pilot for Human {
        fn fly(&self) {
            println!("飞行员:{}", self.name)
        }
    }

    // 实现巫师的trait
    impl Wizard for Human {
        fn fly(&self) {
            println!("巫师:{}", self.name)
        }
    }

    impl Human {
        fn fly(&self) {
            println!("我是人, 我叫:{}", self.name)
        }
    }

    let human = Human {
        name: String::from("老林")
    };
    human.fly(); // 我是人, 我叫:老林
    // 那如何调用Pilot和Wizard上的fly?
    // 通过如下形式:
    Pilot::fly(&human);
    Wizard::fly(&human);
    // 但是, 如果例子稍微改下:
    // Animal有一个baby_name方法
    trait Animal {
        fn baby_name() -> String;
    }

    struct Dog;

    impl Dog {
        // Dog自己实现了一个
        fn baby_name() -> String {
            String::from("this is spot")
        }
    }

    impl Animal for Dog {
        fn baby_name() -> String {
            String::from("this is animal")
        }
    }
    // 这样, Dog自己实现了一个baby_name;
    // Animal为Dog也实现了一个baby_name;
    println!("Dog: {}", Dog::baby_name());
    // 因为这次没有参数, 所以只能使用这种方式来确定它是Animal上的baby_name
    println!("Animal: {}", <Dog as Animal>::baby_name());

    // 4. supertrait, 也就是trait依赖于某个trait, 被依赖的trait就是当前trait的supertrait
    // OutlinePrint依赖于fmt::Display这个trait
    trait OutlinePrint: fmt::Display {
        fn outline_print(&self) {
            let output = self.to_string();
            let len = output.len();
            println!("{}", "*".repeat(len + 4));
            println!("*{}*", " ".repeat(len + 2));
            println!("{}", output);
            println!("*{}*", " ".repeat(len + 2));
            println!("{}", "*".repeat(len + 4));
        }
    }

    struct Point {
        x: i32,
        y: i32
    }

    // 虽然你我们上面已经在trait中默认实现了outline_print, 我们是可以不实现outline_print的
    // 但是还没实现fmt::Display! 所以还是报错
    impl OutlinePrint for Point {}
    // 实现fmt::Display
    impl fmt::Display for Point {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "({}, {})", self.x, self.y)
        }
    }
    let point = Point {x: 2, y: 3};
    point.outline_print();

    // 5.newtype模式, 由于孤儿模式的存在, 只有当trait或者类型在本地的时候, 才能为该类型, 实现这个trait ,可以使用newtype绕开此类型
    // 我们可以通过tupe struct(元组结构体) 创建一个新的类型
    // 假如我们想为Vec实现Display这个trait, 实际上Vec和Display都不在我们本地
    // 我们利用一个struct将Vec包裹
    struct Wrapper(Vec<String>);

    impl fmt::Display for Wrapper {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            write!(f, "[{}]", self.0.join(", "))
        }
    }
    let w = Wrapper(vec![
        String::from("hello"),
        String::from("world")
    ]);
    println!("{}", w.to_string())


}
